#pragma once

#include <iostream>
#include <cstdlib>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/wait.h>
#include "Log.hpp"

Log lg;
const int defaultfd = -1;
const uint16_t defaultport = 8888;
const std::string defaultip = "0.0.0.0";
const int backlog = 10;
enum
{
    UsageError = 1,
    SocketError,
    BindError,
    LisenError

};
class TcpServer
{
public:
    TcpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip) : _listensock(defaultfd), _port(port), _ip(ip)
    {
    }
    void InitServer()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            lg(Fatal, "create socket err : errno %d strerror %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, "create socket success sockfd : %d", _listensock);
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        inet_aton(_ip.c_str(), &(local.sin_addr));

        if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            lg(Fatal, "bind socket err : errno %d strerror %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind socket success sockfd : %d", _listensock);

        // Tcp是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种，一直在等待连接到来的状态
        if (listen(_listensock, backlog) < 0)
        {
            lg(Fatal, "listen socket err : errno %d strerror %s", errno, strerror(errno));
            exit(LisenError);
        }
        lg(Info, "listen socket success sockfd : %d", _listensock);
    }

    void StartServer()
    {
        for (;;)
        {
            // lg(Info, "tcpserver is running ...");
            // sleep(1);

            // 1. 获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "accept error: errno %d strerror %s", errno, strerror(errno));
                continue;
            }

            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);
            // lg(Info, "get a new link..., sockfd: %d", sockfd);
            // 2. 根据新连接来进行通信
            // version 1
            // Service(sockfd, clientip, clientport);
            // close(sockfd);

            //version 2//多进程版
            pid_t id = fork();
            if(id == 0)
            {
                close(_listensock);
                //child
                if(fork() > 0) exit(0);
                Service(sockfd, clientip, clientport);
                close(sockfd);
                exit(0);
            }
            close(sockfd);
            pid_t rid = waitpid(id,nullptr,0);
            
        }
    }

    void Service(int sockfd, const std::string &clientip, const uint16_t &clientport)
    {
        char inbuffer[4096];
        while(true)
        {
            bzero(inbuffer,sizeof(inbuffer));
            ssize_t n = read(sockfd,inbuffer,sizeof(inbuffer));
            if(n > 0)
            {
                inbuffer[n] = 0;
                std::cout<<"client say# "<<inbuffer<<std::endl;
                std::string echo_string = "tcpserver echo# ";
                echo_string += inbuffer;
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
            else if (n == 0)
            {
                lg(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
                break;
            }
            else
            {
                lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
                break;
            }
        }
    }
    ~TcpServer()
    {
    }

private:
    int _listensock;
    uint16_t _port;
    std::string _ip;
};